const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class MyPromise {
    constructor(fn) {
        // try catch 捕获回调函数执行异常
        try {
            fn(this.resolve, this.reject);
        } catch(e) {
            this.reject(e);
        }
    }

    // 状态， 初始状态为pending， 只可以改变一次
    status = PENDING; 
    // resolve时的值
    value = undefined;
    // reject时的原因
    reason = undefined;
    // 存放成功回调数组
    succCbArr = [];
    // 存放失败回调数组
    failCbArr = [];

    resolve = result => {
        // 只能从 pending -> fulfilled
        if (this.status === PENDING) {
            this.status = FULFILLED;
            this.value = result;
            while(this.succCbArr[0]) {
                this.succCbArr.shift()();
            }
        } else {
            return;
        }
    }

    reject = error => {
        // 只能从 pending -> rejected
        if (this.status === PENDING) {
            this.status = REJECTED;
            this.reason = error;
            while(this.failCbArr[0]) {
                this.failCbArr.shift()();
            }
        } else {
            return;
        }
    }

    then(succCb, failCb) {
        // 复写成功回调函数，如果不是函数，将值穿下一个then
        succCb = typeof succCb == 'function' ? succCb : value => value;
        // 复写失败回调函数，如果不是函数，将值穿下一个catch
        failCb = typeof failCb == 'function' ? failCb : reason => { throw reason };
        // 链式调用，返回一个promise
        const promise2 = new MyPromise((resolve, reject) => {
            // 如果当前状态是成功，执行成功回调
            if (this.status === FULFILLED) {
                // setTimeout 原因是此时 promsie2 需要在 resolve/reject 以后才存在
                setTimeout(() => {
                    try {
                        const x = succCb(this.value);
                        // 判断返回值是否是一个promise
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                }, 0)
                
            // 如果当前状态是失败，执行失败回调
            } else if (this.status === REJECTED) {
                setTimeout(() => {
                    try {
                        const x = failCb(this.reason);
                        // 判断返回值是否是一个promise
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                }, 0)
            // 如果还在pending， 将回调函数存起来
            } else {
                this.succCbArr.push(() => {
                    setTimeout(() => {
                        try {
                            const x = succCb(this.value);
                            // 判断返回值是否是一个promise
                            resolvePromise(promise2, x, resolve, reject);
                        } catch (e) {
                            reject(e);
                        }
                    }, 0)
                });
                this.failCbArr.push(() => {
                    setTimeout(() => {
                        try {
                            const x = failCb(this.reason);
                            // 判断返回值是否是一个promise
                            resolvePromise(promise2, x, resolve, reject);
                        } catch (e) {
                            reject(e);
                        }
                    }, 0)
                });
            }
        });
        return promise2;
    }
    // then 的 failCb
    catch(failCallback) {
        return this.then(undefined, failCallback);
    }


    // 不管是 成功还是失败都执行，然后将值顺序传递,返回promsie
    // callback 可以是异步的，此时 finally 以后的then 需要在 finally执行完以后才能执行,需要  MyPromise.resolve 包裹
    finally(callback) {
        return this.then(value => {
            return MyPromise.resolve(callback()).then(() => value);
            // callback();
            // return value;
        }, err => {
            return MyPromise.resolve(callback()).then(undefined, () => { throw err });
        });
    }


    // resolve 接受一个参数，如果是普通值，将值通过resolve包裹， 如果是promise，直接返回
    // 返回的是一个promise
    // Promise.resolve(value).then()
    static resolve(value) {
        if (value instanceof MyPromise) {
            return value;
        } else {
            return new MyPromise((resolve, reject) => {
                resolve(value);
            });
        }
    }

    // reject 接受一个参数，如果是普通值，将值通过resolve包裹， 如果是promise，直接返回
    // 返回的是一个promise
    // Promise.reject(value).then()
    static reject(value) {
        if (value instanceof MyPromise) {
            return new MyPromise((resolve, reject) => {
                value.then(value => {
                    reject(value);
                }, err => {
                    reject(err);
                })
            });
            
            return value;
        } else {
            return new MyPromise((resolve, reject) => {
                reject(value);
            });
        }
    }

    // all 接受一个参数，这个参数是数组, 有一个 catch 就所有都catch
    // 返回的是一个promise
    // Promise.all([]).then()
    static all(array) {
        array = Array.from(array);
        if (!array.length) {
            return;
        }
        return new MyPromise((resolve, reject) => {
            const result = [];
            let count = 0;
            function addData(i, value) {
                result[i] = value;
                count++;
                if (count === array.length) {
                    resolve(result);
                }
            }
            for (let i = 0; i < array.length; i++) {
                if (array[i] instanceof MyPromise) {
                    array[i].then(value => {
                        addData(i, value)
                    }, err => {
                        reject(err);
                    });
                } else {
                    addData(i, array[i]);
                }
            }
        })
    }

    // race 接受一个参数，这个参数是数组, 数组是promise
    // 返回的是一个promise，等同于最先完成的 promise
    // Promise.all([]).then()
    static race(array) {
        array = Array.from(array);
        if (!array.length) {
            return;
        }
        return new MyPromise((resolve, reject) => {
            let flag = false;

            for (let i = 0; i < array.length; i++) {
                if (flag) {
                    break;
                }
                if (array[i] instanceof MyPromise) {
                    array[i].then(value => {
                        resolve(value);
                        flag = true;
                    }, err => {
                        reject(err);
                        flag = true;
                    });
                } else {
                    resolve(array[i]);
                    flag = true;
                }
            }
        })
    }

    // allSettled 接受一个数组，返回一个 promise， 这个 promise 只有 fulfilled 状态
    // 返回值是一个数组，数组的每个元素是个对象，包括 状态(status) 和 值(value/reason)
    static allSettled(array) {
        array = Array.from(array);
        if (!array.length) {
            return;
        }
        return new MyPromise(resolve => {
            const result = [];
            let count = 0;
            function addData(i, value) {
                result[i] = value;
                count++;
                if (count === array.length) {
                    resolve(result);
                }
            }
            for (let i = 0; i < array.length; i++) {
                if (array[i] instanceof MyPromise) {
                    array[i].then(value => {
                        addData(i, {
                            status: FULFILLED,
                            value
                        });
                    }, err => {
                        addData(i, {
                            status: REJECTED,
                            reason: err
                        })
                    });
                } else {
                    addData(i, {
                        status: FULFILLED,
                        value: array[i]
                    });
                }
            }
        })
    }

    // allSettled 接受一个数组，数组的 promise 有一个是 FUIFILLED 时，结果就是 fulfilled, 否则 rejected
    // 返回的是一个promise，
    static any(array) {
        array = Array.from(array);
        if (!array.length) {
            return;
        }
        return new MyPromise((resolve, reject) => {
            const flag = false;
            const rejectResult = [];
            let count = 0;
            function addData(i, value) {
                rejectResult[i] = value;
                count++;
                if (count === array.length && !flag) {
                    reject(rejectResult);
                }
            }
            for (let i = 0; i < array.length; i++) {
                if (array[i] instanceof MyPromise) {
                    array[i].then(value => {
                        if (!flag) {
                            resolve(value);
                            flag = true;
                        }
                    }, err => {
                        addData(i, err)
                    });
                } else {
                    if (!flag) {
                        resolve(array[i]);
                        flag = true;
                    }
                }
            }
        })
    }
}

// 如果返回了当前 promise， 报类型错误，因为会无限自调用
// 判断返回值是否是一个promise，如果是promise， 继续链式调用，否则直接resolve
function resolvePromise(promise2, x, resolve, reject) {
    if (promise2 == x) {
        return reject(new TypeError('Chaining cycle detected for promise'));
    }
    if (x instanceof MyPromise) {
        x.then(resolve, reject);
    } else {
        resolve(x);
    }
}

module.exports = MyPromise;